﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

using LowLevelGraphics.Types.Interval;

namespace LowLevelGraphics.Filter
{
    public delegate int ColorDelegate(Color _color);

    /// <summary>
    /// Bring up only colors that are contained in indexed list.
    /// i.e. all different colors will be added in an index lookup list, 
    /// then the will be sorted. 
    /// 
    /// color.ToArgb() => this int value will be stored.
    /// 
    /// Then the int values will be sorted.
    /// 
    /// A given Interval determines, which Indexed Colors will be shown,
    /// the rest will be drawn with the specified background color
    /// 
    /// </summary>
    public class SortedColorFilter : BaseForeBackgroundColorFilter
    {
        protected IntInterval m_IntInterval = new IntInterval(0, 10000);
        protected bool m_bReverseOrder = false;

        protected ColorDelegate m_ColorDelegate = new ColorDelegate(delegate(Color _color) { return _color.ToArgb(); });
        /// <summary>
        /// 
        /// </summary>
        public SortedColorFilter()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_sortedColorFilter"></param>
        internal SortedColorFilter(SortedColorFilter _sortedColorFilter)
        {
            m_IntInterval = _sortedColorFilter.m_IntInterval;
            m_bReverseOrder = _sortedColorFilter.m_bReverseOrder;
        }

        /// <summary>
        /// Gets or sets color delegate
        /// </summary>
        public ColorDelegate ColorDelegate
        {
            get { return m_ColorDelegate; }
            set { m_ColorDelegate = value; }
        }

        /// <summary>
        /// Gets or sets reverse order
        /// </summary>
        public bool ReverseOrder
        {
            get { return m_bReverseOrder; }
            set { m_bReverseOrder = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int nWidth = _bitmap.Width;
            int nHeight = _bitmap.Height;
            int y = 0;
            int x = 0;
            
            //Create correct capacity to speed up dramatically
            List<int> aInt = new List<int>(nHeight * nWidth);
            int nColorValue = -1;
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    nColorValue = m_ColorDelegate(_bitmap.GetPixel(x, y));
                    aInt.Add(nColorValue);
                }
            }

            aInt.Sort();
            if (m_bReverseOrder) aInt.Reverse();

            //Store indices in Dictionary for fast lookup
            Dictionary<int, int> aDict = new Dictionary<int, int>();
            int i = 0;
            foreach (int nValue in aInt)
            {
                if (!aDict.ContainsKey(nValue)) aDict.Add(nValue, i++);
            }

            Color color = Color.Transparent;

            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    color = _bitmap.GetPixel(x,y);
                    nColorValue = m_ColorDelegate(color);
                    _bitmap.SetPixel(x, y, m_IntInterval.Contains(aDict[nColorValue]) ? color : m_ColorBackground);
                }
            }
            
            return _bitmap;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new SortedColorFilter(this);
        }
    }
}
